#include "CWheelTimerMgr.h"
#include "CTimer.h"
#include "CExecTimerInfoList.h"
#include <string.h>

namespace TB
{
	UINT64 CWheelTimerMgr::m_aTimeOffsets[TIMER_LIST_COUNT] = {};

	CWheelTimerMgr::CWheelTimerMgr(volatile UINT64* pqwCurTime)
	{
		//如果没初始化，就初始化一下
		UINT64 qwTimerCycle = (1 << TIMER_CYCLE);
		if (m_aTimeOffsets[0] != qwTimerCycle) {
			m_aTimeOffsets[0] = qwTimerCycle;
			for (int i = 1; i != TIMER_LIST_COUNT; ++i) {
				UINT64 q = qwTimerCycle;
				for (int j = 0; j != i; ++j) {
					q <<= TIMER_CYCLE;
				}
				m_aTimeOffsets[i] = q + m_aTimeOffsets[i - 1];
			}
		}
		if (pqwCurTime != nullptr)
			m_pqwCurTime = pqwCurTime;
#ifdef _USING_CLI
		m_aTimers = gcnew array<PTR(CExecTimerInfoList)>(TIMER_LIST_COUNT);
#else
		memset(m_aTimers, 0, sizeof(CExecTimerInfoList*) * TIMER_LIST_COUNT);
#endif
		m_poExtTimers = QNEW CVector(STimerInfo)();
		m_poTimerMgr = QNEW CObjectResMgr<PTR_OR_VAL(CTimer)>(
			NEW_DELEGATE(
				QPACK(DNewObj<CTimer>),
				this, CWheelTimerMgr::_NewTimer,
				DELEGATE_PLACEHOLDERS(, std::placeholders::_1)
			)
		);
	}

#ifndef _USING_CLI
	CWheelTimerMgr::~CWheelTimerMgr() {
		for (int i = 0; i != TIMER_LIST_COUNT; ++i)
			SAFE_DELETE(m_aTimers[i]);
		SAFE_DELETE(m_poExtTimers);
		m_poTimerMgr->ReleaseAll();
		SAFE_DELETE(m_poTimerMgr);
	}
#endif

	CUniquePtr(CTimer) CWheelTimerMgr::_NewTimer(UINT16)
    {
        CUniquePtr(CTimer) poTimer(QNEW CTimer());
		return poTimer;
    }

	UINT32 CWheelTimerMgr::Poll(UINT64 qwDeltaMilliSeconds)
	{
		auto qwCurTime = GetCurTime();
		if (m_aTimers[0] == NULL_PTR) { //如果没初始化，先初始化一下
			for (UINT32 i = 0; i != TIMER_LIST_COUNT; ++i) {
				m_aTimers[i] = QNEW CExecTimerInfoList();
				m_aTimers[i]->m_qwEndTime = qwCurTime + m_aTimeOffsets[i];
			}
		}
		m_qwCurTime += qwDeltaMilliSeconds; // 只设置本地变量，而不设置m_pqwCurTime
		UINT32 dwCount = _ExecTimer(m_dwMaxCountPerPoll);
		return dwCount;
	}

	UINT32 CWheelTimerMgr::_ExecTimer(UINT32 dwMaxCount)
	{
		PTR(CExecTimerInfoList) poTimers = m_aTimers[0];
		if (poTimers == NULL_PTR)
			return 0;

		UINT32 dwCount = 0;
		for (; dwMaxCount == 0 || dwCount < dwMaxCount; _Tick(0)) {
			auto qwCurTime = GetCurTime();
			if (qwCurTime < poTimers->m_qwEndTime - (1u << TIMER_CYCLE) + poTimers->m_wOffset)
				break;
			if (poTimers->m_wOffset >= poTimers->m_oExecTimerInfo.size())
				continue;
			PTR(CExecTimerInfo) poExecTimerInfo = TO_PTR2(poTimers->m_oExecTimerInfo.at(poTimers->m_wOffset));
#ifdef _USING_CLI
			if (poExecTimerInfo == NULL_PTR)
				continue;
#endif
			for (; (dwMaxCount == 0 || dwCount < dwMaxCount) && !poExecTimerInfo->m_oExecTimerInfo.empty(); poExecTimerInfo->m_oExecTimerInfo.pop_front()) {
				CONST_REF(STimerUID) rsTimerUID = poExecTimerInfo->m_oExecTimerInfo.at(0).m_sTimerUID;
				PTR(CTimer) poTimer = m_poTimerMgr->GetObj(rsTimerUID.ToUINT64());
				if (poTimer != NULL_PTR) {
					++dwCount;
					if (IS_NOT_NULL_DELEGATE(poTimer->m_cbOnTimer)) {
						poTimer->m_cbOnTimer(rsTimerUID, poTimer->m_dwCurrent, poTimer->m_dwCount);
					}
					if (IsTimerRunning(rsTimerUID)) {
						if (poTimer->m_dwCount == 0 || poTimer->m_dwCurrent < poTimer->m_dwCount - 1) {
							if (poTimer->m_dwCurrent != (UINT32)-1)
								++poTimer->m_dwCurrent;
							UINT64 qwExecTime = 0;
							if (poTimer->m_bAutoFix && poTimer->m_dwCurrent != (UINT32)-1 &&
								((UINT64)-1 - poTimer->m_qwFirstTimeoutTime) / poTimer->m_dwCurrent > poTimer->m_qwIntervalMilliSeconds)
							{
								qwExecTime = poTimer->m_qwFirstTimeoutTime + poTimer->m_qwIntervalMilliSeconds * poTimer->m_dwCurrent;
							}
							else
								qwExecTime = qwCurTime + poTimer->m_qwIntervalMilliSeconds;
							_AddTimer(rsTimerUID, qwExecTime);
						}
						else
							StopTimer(rsTimerUID);
					}
				}
			}
		}
		return dwCount;
	}

	void CWheelTimerMgr::_Tick(UINT16 wLevel)
	{
		if (wLevel > TIMER_LIST_COUNT)//不合法参数
			return;
		if (wLevel == TIMER_LIST_COUNT) {//时间轮集合中的timer全部执行完毕，需要将后面的timer放到时间轮集合中来
			UINT32 extTimersLen = m_poExtTimers->size();
			if (extTimersLen != 0) {
				CVector(STimerInfo) extTimers;
				m_poExtTimers->swap(extTimers);
				for (UINT32 i = 0; i != extTimersLen; ++i) {
					_AddTimer(extTimers[i].m_sTimerUID, extTimers[i].m_qwExecTime);
				}
			}
			return;
		}
		PTR(CExecTimerInfoList) poCurTimers = m_aTimers[wLevel];
		UINT16 wPrevOffset = poCurTimers->m_wOffset;
		if (wPrevOffset < poCurTimers->m_oExecTimerInfo.size()) {
			CExecTimerInfo& preExecInfo = poCurTimers->m_oExecTimerInfo[wPrevOffset];
			if (preExecInfo.m_oExecTimerInfo.empty() == false) {
				if (wLevel == 0) {
					return;
				}
				// 从该片时间轮中取出一格timer，放入前面的时间轮中
				for (; !preExecInfo.m_oExecTimerInfo.empty();preExecInfo.m_oExecTimerInfo.pop_front()) {
					_AddTimerInfo(wLevel - 1, preExecInfo.m_oExecTimerInfo[0]);
				}
			}
		}
		++poCurTimers->m_wOffset;
		if (poCurTimers->m_wOffset >= (1 << TIMER_CYCLE)){ //该片时间轮中的timer全部执行完毕，需要将后面一片时间轮的一格timer拿过来
			UINT64 offsetTime = m_aTimeOffsets[wLevel];
			if (wLevel != 0) {
				offsetTime -= m_aTimeOffsets[wLevel - 1];
			}
			poCurTimers->m_qwEndTime += offsetTime;
			poCurTimers->m_wOffset = 0;
			_Tick(wLevel + 1);
		}
	}

    STimerUID CWheelTimerMgr::StartTimer(UINT64 dwMilliSeconds, CONST_PTR_OR_REF(DOnTimer) ronTimer, bool bAutoFix)
    {
		return StartTimer(dwMilliSeconds, 0, dwMilliSeconds, ronTimer, bAutoFix);
    }

    STimerUID CWheelTimerMgr::StartTimer(UINT64 dwMilliSeconds, UINT32 dwCount, CONST_PTR_OR_REF(DOnTimer) ronTimer, bool bAutoFix)
    {
		return StartTimer(dwMilliSeconds, dwCount, dwMilliSeconds, ronTimer, bAutoFix);
    }

    STimerUID CWheelTimerMgr::StartTimer(UINT64 dwMilliSeconds, UINT32 dwCount, UINT64 dwFirstTimeoutMilliSeconds, CONST_PTR_OR_REF(DOnTimer) ronTimer, bool bAutoFix)
    {
		auto qwCurTime = GetCurTime();
		PTR(CTimer) poTimer = m_poTimerMgr->CreateObj(0);
		poTimer->m_qwFirstTimeoutTime = qwCurTime + dwFirstTimeoutMilliSeconds;
		poTimer->m_qwIntervalMilliSeconds = dwMilliSeconds;
		poTimer->m_dwCount = dwCount;
		poTimer->m_cbOnTimer = ronTimer;
		poTimer->m_bAutoFix = bAutoFix;
		_AddTimer(poTimer->GetTimerUID(), poTimer->m_qwFirstTimeoutTime);
		return poTimer->GetTimerUID();
    }

    BOOLN CWheelTimerMgr::IsTimerRunning(CONST_REF(STimerUID) rsTimerUID) QCONST_FUNC
    {
		if (!rsTimerUID)
			return false;
		PTR(CTimer) poTimer = m_poTimerMgr->GetObj(rsTimerUID.ToUINT64());
        return poTimer != NULL_PTR;
    }

    void CWheelTimerMgr::StopTimer(CONST_REF(STimerUID) rsTimerUID)
    {
        m_poTimerMgr->ReleaseObj(rsTimerUID.ToUINT64());
		// TODO: 如果要从队列里面删除，记得改Poll里面的队列遍历逻辑，以免迭代器失效
    }

	UINT64 CWheelTimerMgr::GetNextPollTime() const
	{
		PTR(CExecTimerInfoList) poTimers = m_aTimers[0];
		if (poTimers == NULL_PTR)
			return (UINT64)-1;
		for (UINT16 i = poTimers->m_wOffset; i != poTimers->m_oExecTimerInfo.size(); ++i)
		{
			if (!poTimers->m_oExecTimerInfo[i].m_oExecTimerInfo.empty())
				return poTimers->m_qwEndTime - (1u << TIMER_CYCLE) + poTimers->m_wOffset;
		}
		PTR(CExecTimerInfoList) poTimers1 = m_aTimers[1];
		if (poTimers1 == NULL_PTR || poTimers1->m_oExecTimerInfo.empty() || !poTimers1->m_oExecTimerInfo[0].m_oExecTimerInfo.empty())
			return poTimers->m_qwEndTime;
		return poTimers->m_qwEndTime + (1u << TIMER_CYCLE);
	}

	void CWheelTimerMgr::_AddTimer(CONST_REF(STimerUID) rsTimerUID, UINT64 qwExecTime)
	{
		BOOLN bAdd = false;
		for (UINT16 level = 0; level != TIMER_LIST_COUNT; ++level) {
			PTR(CExecTimerInfoList) poCurTimers = m_aTimers[level];
			if (poCurTimers == NULL_PTR)
				poCurTimers = m_aTimers[level] = QNEW CExecTimerInfoList();
			if (qwExecTime >= poCurTimers->m_qwEndTime)
				continue;
			bAdd = true;
			UINT64 qwBeginTime = poCurTimers->m_qwEndTime - (level == 0 ? m_aTimeOffsets[level] : m_aTimeOffsets[level] - m_aTimeOffsets[level - 1]);
			UINT64 qwStep = (m_aTimeOffsets[level] - (level == 0 ? 0 : m_aTimeOffsets[level - 1])) >> TIMER_CYCLE;
			UINT16 wOffset = (UINT16)((qwExecTime - qwBeginTime) / qwStep);

			if (poCurTimers->m_oExecTimerInfo.size() <= wOffset)
				poCurTimers->m_oExecTimerInfo.resize(wOffset + 1);
			PTR(CExecTimerInfo) poExecTimerInfo = TO_PTR2(poCurTimers->m_oExecTimerInfo.at(wOffset));
#ifdef _USING_CLI
			if (poExecTimerInfo == NULL_PTR)
				poExecTimerInfo = TO_PTR(poCurTimers->m_oExecTimerInfo)[wOffset] = QNEW CExecTimerInfo();
#endif
			poExecTimerInfo->m_oExecTimerInfo.push_back(STimerInfo(qwExecTime, rsTimerUID));
			break;
		}
		if (!bAdd) {
			m_poExtTimers->push_back(STimerInfo(qwExecTime, rsTimerUID));
		}
	}

	void CWheelTimerMgr::_AddTimerInfo(UINT16 wLevel, REF(STimerInfo) rsInfo)
	{
		PTR(CExecTimerInfoList) poCurTimers = m_aTimers[wLevel];
		UINT64 offsetTime = m_aTimeOffsets[wLevel];
		if (wLevel != 0) {
			offsetTime -= m_aTimeOffsets[wLevel - 1];
		}
		UINT64 beginTime = poCurTimers->m_qwEndTime - offsetTime;
		if (rsInfo.m_qwExecTime < beginTime) {
			rsInfo.m_qwExecTime = beginTime;
		}
		UINT64 nStep = offsetTime >> TIMER_CYCLE;
		UINT16 offset = UINT16((rsInfo.m_qwExecTime - beginTime) / nStep);
		if (offset < poCurTimers->m_wOffset) {
			offset = poCurTimers->m_wOffset;
		}
		if (offset >= poCurTimers->m_oExecTimerInfo.size()) {
			poCurTimers->m_oExecTimerInfo.resize(offset + 1);
		}
		poCurTimers->m_oExecTimerInfo[offset].m_oExecTimerInfo.push_back(rsInfo);
	}
};
